#include <sstream>

#include "states.h"
#include "engine-utils.h"

using namespace std;



void PlayerInfo::censor(const PlayerMask& mask)
{
	censorAll(playerNames, nameMasks, mask);
}

void PlayerInfo::serialize(ostream& ostr) const
{
	ostr << getPrefix() << ' ' << numPlayers;
	for (int i = 0; i < numPlayers; i++)
	{
		ostr << ' ' << nameMasks[i];
		if (HIDDEN != nameMasks[i])
		{
			ostr << ' ';
			serializeString(playerNames[i], ostr);
		}
	}
	ostr << ' ';
	currentTurn.serialize(ostr);
}

void PlayerInfo::serialize(const PlayerMask& mask, ostream& ostr) const
{
	censorAndSerialize(*this, mask, ostr);
}

void PlayerInfo::unserialize(istream& istr)
{
	if (!prefixMatch(*this, istr))
	{
		istr.setstate(ios::failbit);
		return;
	}
	istr >> numPlayers;
	// if numplayers is obviously wrong, quit now before we try to read 3 billion masks or something
	if (numPlayers < 0 || numPlayers > 64)
	{
		istr.setstate(ios::failbit);
		return;
	}
	nameMasks.resize(numPlayers);
	playerNames.resize(numPlayers);	
	for (int i = 0; i < numPlayers; i++)
	{
		istr >> nameMasks[i];
		if (HIDDEN != nameMasks[i])
			unserializeString(playerNames[i], istr);
	}
	currentTurn.unserialize(istr);
}



void Map::censor(const PlayerMask& mask)
{
	censorAll(terrain, impassible, visibility, mask);
}

void Map::serialize(ostream& ostr) const
{
	ostr << getPrefix() << ' ' << width << ' ' << height << ' ' << gridtype;
	for (unsigned int i = 0; i < visibility.size(); i++)
	{
		ostr << ' ' << visibility[i];
		if (HIDDEN != visibility[i])
			ostr << ' ' << terrain[i] << ' ' << boolalpha << impassible[i];
	}
}

void Map::serialize(const PlayerMask& mask, ostream& ostr) const
{
	censorAndSerialize(*this, mask, ostr);
}

void Map::unserialize(istream& istr)
{
	if (!prefixMatch(*this, istr))
	{
		istr.setstate(ios::failbit);
		return;
	}
	istr >> width >> height >> gridtype;
	if (width < 0 || height < 0)
	{
		istr.setstate(ios::failbit);
		return;
	}
	int num = width*height;
	visibility.resize(num);
	terrain.resize(num);
	impassible.resize(num);
	for (int i = 0; i < num; i++)
	{
		istr >> visibility[i];
		if (HIDDEN != visibility[i])
			istr >> terrain[i] >> boolalpha >> impassible[i];
	}
}




void CamperAttributes::censor(const PlayerMask& mask)
{
	censorItem(vision, visionMask, mask);
	censorItem(strength, strengthMask, mask);
	censorItem(speed, speedMask, mask);
}

void CamperAttributes::serialize(ostream& ostr) const
{
	ostr << getPrefix() << ' ';
	maskSerialize(vision, visionMask, ostr);
	ostr << ' ';
	maskSerialize(strength, strengthMask, ostr);
	ostr << ' ';
	maskSerialize(speed, speedMask, ostr);
}

void CamperAttributes::serialize(const PlayerMask& mask, ostream& ostr) const
{
	censorAndSerialize(*this, mask, ostr);
}

void CamperAttributes::unserialize(istream& istr)
{
	if (!prefixMatch(*this, istr))
	{
		istr.setstate(ios::failbit);
		return;
	}
	maskUnserialize(vision, visionMask, istr);
	maskUnserialize(strength, strengthMask, istr);
	maskUnserialize(speed, speedMask, istr);
}



void CamperStatus::censor(const PlayerMask& mask)
{
	censorItems(pos, jailed, posMask, mask);
	censorItem(movementPts, ptsMask, mask);
	censorItem(stance, stanceMask, mask);
}

void CamperStatus::serialize(ostream& ostr) const
{
	ostr << getPrefix();
	ostr << ' ' << posMask;
	if (HIDDEN != posMask)
	{
		ostr << ' ';
		pos.serialize(ostr);
		ostr << ' ' << boolalpha << jailed;
	}
	ostr << ' ';
	maskSerialize(movementPts, ptsMask, ostr);
	ostr << ' ';
	maskSerialize(stance, stanceMask, ostr);
}

void CamperStatus::serialize(const PlayerMask& mask, ostream& ostr) const
{
	censorAndSerialize(*this, mask, ostr);
}

void CamperStatus::unserialize(istream& istr)
{
	if (!prefixMatch(*this, istr))
	{
		istr.setstate(ios::failbit);
		return;
	}
	istr >> posMask;
	if (HIDDEN != posMask)
	{
		pos.unserialize(istr);
		istr >> boolalpha >> jailed;
	}
	maskUnserialize(movementPts, ptsMask, istr);
	maskUnserialize(stance, stanceMask, istr);
}
